/*
	@Author：TangYi

	Description:一个通用的Windows C语言的轻型网络框架
	风格说明：虽然这是一个Windows程序，但试用linux的命名风格.

*/

#include "connection.h"
#include "debug_log.h"
#include "lock.h"
#include "config.h"
#include "list.h"
#include "vs_world.h"

extern cycle_t* g_cycle;
extern vs_world_t* g_vs_world;
static hashtable_t global_con_hashtable;

#define BUF_SIZE 4 * 1024

hashtable_t* init_con()
{
	dbg_assert(!hash_create(&global_con_hashtable,1024,NULL));
	return &global_con_hashtable;
}

connection_t* add_new_connection(SOCKET socket)
{
	connection_t* con;
	unsigned long mode = 1;
	con = (connection_t*)malloc(sizeof(connection_t));
	dbg_assert(con != NULL);
	con->con_socket = socket;
	con->receving_packet = NULL;
	con->obuf = init_circular_buffer(BUF_SIZE);
	con->session = init_session(socket);

	//设置成非阻塞IO
	dbg_assert(!ioctlsocket(socket,FIONBIO,&mode));
	
	lock("vs_con_hashtable_lock");
	dbg_assert(!hash_entry(&global_con_hashtable,(char*)&socket,sizeof(SOCKET),con));
	unlock("vs_con_hashtable_lock");
	
	return con;
}

connection_t* get_connection(SOCKET socket)
{
	connection_t* con = NULL;

	lock("vs_con_hashtable_lock");
	
	hash_find(&global_con_hashtable,(char*)&socket,sizeof(SOCKET),(void**)&con);
	
	unlock("vs_con_hashtable_lock");

	return con;
}

int delete_connection(SOCKET socket)
{
	connection_t* con;
	int ret_code = -1;

	lock("vs_con_hashtable_lock");
	if(!hash_find(&global_con_hashtable,(char*)&socket,sizeof(SOCKET),(void**)&con))
	{
		dispose_session(con->session);
		dispose_circular_buffer(con->obuf);
		free(con);
		dbg_assert(!hash_remove(&global_con_hashtable,(char*)&socket,sizeof(SOCKET)));
		ret_code = 0;
	}
	unlock("vs_con_hashtable_lock");

	return ret_code;
}

int delete_connection(connection_t* con)
{
	SOCKET socket = con->con_socket;
	return delete_connection(socket);
}


//读取套接字，并进行分包
//返回：
//	0	成功，读取完整分包
//	1	失败，没有读取完整分包，下次接着读
//	2	失败，网络断开连接
//	3	失败，超过最大包长度
//	
//对付读半个包的情况：采用非阻塞IO，读不完，下次再读
int read_packet(connection_t* con,packet_t** packet)
{
	packet_t* pkt;
	if(con->receving_packet == NULL)
	{
		pkt = init_packet();
		dbg_assert(pkt != NULL);
		con->receving_packet = pkt;
	}else{
		pkt = con->receving_packet;
	}

	*packet = pkt;

	//首先读取包头，即Data length
	if((sizeof(unsigned long) - pkt->remain.length_data_readed) > 0)
	{
		//首先读取数据部分的长度，转换网络序和本地
		int length_readed = con->receving_packet->remain.length_data_readed;
		int ret = recv(con->con_socket , pkt->remain.length_data + length_readed,
			sizeof(unsigned long) - length_readed, 0);
		//连接断开
		if(ret == 0)
		{
			dispose_packet(pkt);
			con->receving_packet = NULL;
			return 2;
		}else if(ret == SOCKET_ERROR)
		{
			int err = WSAGetLastError();
			//如果没有数据可以读取
			if(err == WSAEWOULDBLOCK)
				return 1;
			else
			{
				//如果发生了错误
				dispose_packet(pkt);
				con->receving_packet = NULL;
				return 2;
			}
		}

		con->receving_packet->remain.length_data_readed += ret;
		//如果还没有读完，则记录已经读到的信息，接着继续读
		if(con->receving_packet->remain.length_data_readed < sizeof(unsigned long))
			return 1;

		//包头的长度已经读完
		unsigned long data_length;
		memcpy(&data_length,con->receving_packet->remain.length_data,sizeof(unsigned long));
		data_length = ntohl(data_length);
		if(data_length > g_cycle->server_config->max_packet_data_length)
		{
			//如果发生了错误
			dispose_packet(pkt);
			con->receving_packet = NULL;
			return 3;
		}
		
		con->receving_packet->data_length = data_length;
		con->receving_packet->buf_length = data_length + sizeof(unsigned long);
		
		con->receving_packet->buf = (char*)malloc(con->receving_packet->buf_length);
		con->receving_packet->data = con->receving_packet->buf + sizeof(unsigned long);
		dbg_assert(con->receving_packet->buf);

		memcpy(con->receving_packet->buf,con->receving_packet->remain.length_data,sizeof(unsigned long));
	}

	//下面读取包的内容，即Data
	if(con->receving_packet->remain.data_readed < con->receving_packet->data_length)
	{
		unsigned long data_readed = con->receving_packet->remain.data_readed;
		int ret = recv(con->con_socket , pkt->data + data_readed,
			con->receving_packet->data_length - data_readed,0);

		//连接断开
		if(ret == 0)
		{
			dispose_packet(pkt);
			con->receving_packet = NULL;
			return 2;
		}else if(ret == SOCKET_ERROR)
		{
			int err = WSAGetLastError();
			//如果没有数据可以读取
			if(err == WSAEWOULDBLOCK)
				return 1;
			else
			{
				//如果发生了错误
				dispose_packet(pkt);
				con->receving_packet = NULL;
				return 2;
			}
		}
		
		con->receving_packet->remain.data_readed += ret;
		if(con->receving_packet->remain.data_readed < con->receving_packet->data_length)
			return 1;
	}

	return 0;
}


int set_session(connection_t* con,char* session_name,void* value,
				pfunc_value_dispose_callback dispose_callback)
{
	return set_session(con->session,session_name,value,dispose_callback);
}

int get_session(connection_t* con,char* session_name,void** value)
{
	return get_session(con->session,session_name,value);
}

int delete_session(connection_t* con,char* session_name)
{
	return delete_session(con->session,session_name);
}


/*****************************************************************************/
//释放包队列的方法
void free_packet_quene(void* quene_list)
{
	list_t* list = (list_t*)quene_list;
	listnode_t* p = list->head;
	while(p != NULL)
	{
		packet_t* pkt = (packet_t*)p->data;
		dispose_packet(pkt);
		p = p->next;
	}
	list_destroy(list,NULL);
}

//产生输入输出队列的锁名
char* yield_packet_quene_lock_name(unsigned long key,char* packet_quene_name)
{
	int packet_quene_name_length = strlen(packet_quene_name);
	char* lock_name = (char*)malloc(packet_quene_name_length + 9);
	dbg_assert(lock_name != NULL);
	sprintf(lock_name,"%08X",key);
	memcpy(lock_name + 8,packet_quene_name,packet_quene_name_length);
	lock_name[packet_quene_name_length + 8] = 0;

	return lock_name;
}

//处理新的连接
void handle_new_connection(connection_t* con)
{
	list_t* recv_packet_quene = list_create();
	list_t* send_packet_quene = list_create();

	set_session(con,"recv_packet_quene",recv_packet_quene,free_packet_quene);
	set_session(con,"send_packet_quene",send_packet_quene,free_packet_quene);
	set_session(con,"recv_packet_quene_lock_name",
		yield_packet_quene_lock_name(con->con_socket,"recv_packet_quene"),free);
	set_session(con,"send_packet_quene_lock_name",
		yield_packet_quene_lock_name(con->con_socket,"send_packet_quene"),free);

	vs_world_add_connection(g_vs_world,con);
}

//注意：删除Connection和关闭socket由创建Connection的过程来完成
void handle_disconnect(connection_t* con)
{
	vs_world_delete_connection(g_vs_world,con);
}

//处理packet
//此处仅仅是做个测试
//扩展，将处理方法放在 g_cycle中，然后扩展
void handle_packet(connection_t* con,packet_t* packet)
{
	list_t* recv_packet_quene = NULL;
	char* lock_name = NULL;

	get_session(con,"recv_packet_quene",(void**)&recv_packet_quene);
	dbg_assert(recv_packet_quene != NULL);

	get_session(con,"recv_packet_quene_lock_name",(void**)&lock_name);
	dbg_assert(lock_name != NULL);
	
	listnode_t* node = list_node_create(packet);
	
	lock(lock_name);

	list_push_back(recv_packet_quene,node);
	
	unlock(lock_name);
}

//从接收队列中POP一个PACKET
packet_t* pop_back_connection_recv_packet(connection_t* con)
{
	list_t* recv_packet_quene = NULL;
	char* lock_name = NULL;
	listnode_t* node = NULL;
	packet_t* packet = NULL;

	get_session(con,"recv_packet_quene",(void**)&recv_packet_quene);
	dbg_assert(recv_packet_quene != NULL);

	get_session(con,"recv_packet_quene_lock_name",(void**)&lock_name);
	dbg_assert(lock_name != NULL);
	
	lock(lock_name);

	node = list_pop_back(recv_packet_quene);
	if(node != NULL)
	{
		packet = (packet_t*)node->data;
		free(node);	//最恨抓BUG
	}
	
	unlock(lock_name);

	return packet;
}

//向发送队列中PUSH一个PACKET
void push_front_connection_send_packet(connection_t* con,packet_t* packet)
{
	list_t* send_packet_quene = NULL;
	char* lock_name = NULL;

	get_session(con,"send_packet_quene",(void**)&send_packet_quene);
	dbg_assert(send_packet_quene != NULL);

	get_session(con,"send_packet_quene_lock_name",(void**)&lock_name);
	dbg_assert(lock_name != NULL);
	
	listnode_t* node = list_node_create(packet);

	lock(lock_name);

	list_push_front(send_packet_quene,node);
	
	unlock(lock_name);
}

//DO NOTHING
//在WINDOWS中此处应为处理OOB数据包，但此处不做处理
int connection_on_exceptions(connection_t* con)
{
	dbg_print("OOB data should be handled!");
	return 0;
}

//此处操纵的为非阻塞IO
int connection_on_write(connection_t* con)
{
	circular_buffer_t* obuf = con->obuf;
	int n = send(con->con_socket, 
		get_start_of_circular_buffer(obuf), length_of_cicular_buffer(obuf), 0);

	if(n < 0)
	{
		int error_no = WSAGetLastError();
		if(error_no != WSAEWOULDBLOCK)
		return -1;
	}else
	{
		remove_from_circular_biffer(obuf,n);
		return 0;
	}
}

//此处操纵的为非阻塞IO
int connection_on_read(connection_t* con)
{
	packet_t* pkt = NULL;
	int res;
	int ret = read_packet(con,&pkt);
	switch(ret)
	{
	case 0:
		handle_packet(con,pkt);
		con->receving_packet = NULL;
		
		res = 0;
		break;
	case 1:
		//没有读完，下次继续
		res = 0;
		break;
	case 2:
		
		res = -1;
		break;
	case 3:
		dbg_print("Packet is TOO long!");
		res = -1;
		break;
	}

	return res;
}

//说明：在此种情况下，PACKET的大小不能大于OBUF的BUF_SIZE
void flush_packets_to_output_buffer(connection_t* con)
{
	list_t* send_packet_quene = NULL;
	packet_t* packet = NULL;
	char* send_packet_quene_lock_name = NULL;

	get_session(con,"send_packet_quene",(void**)&send_packet_quene);
	dbg_assert(send_packet_quene != NULL);
	get_session(con,"send_packet_quene_lock_name",(void**)&send_packet_quene_lock_name);
	dbg_assert(send_packet_quene_lock_name != NULL);

	lock(send_packet_quene_lock_name);

	listnode_t* packet_node = list_pop_front(send_packet_quene);
	//发送一个，删除一个
	while(packet_node)
	{
		//得到此包
		packet = (packet_t*)packet_node->data;
		//发送
		if(packet->buf_length < space_of_circular_buffer(con->obuf))
		{
			//写入到输出缓冲
			write_to_circular_buffer(con->obuf,packet->buf,packet->buf_length);
			dispose_packet(packet);
			free(packet_node);
			packet_node = list_pop_front(send_packet_quene);
		}else
		{
			list_push_front(send_packet_quene,packet_node);
			break;
		}
	}

	unlock(send_packet_quene_lock_name);
}

//发送所有的包
void flush_all_connections_packets()
{		
	hashbucket_t *p,*q;
	p = global_con_hashtable.head;

	while (p)
	{
		q = p;
		p = p->next;
		connection_t* con = (connection_t*)q->data;

		flush_packets_to_output_buffer(con);
	}
}